import time
from fastapi import FastAPI, Query, Header, HTTPException, Depends
from fastapi.responses import FileResponse
from process import settings, libaray
from common.model import *
from process.convertor import AudioMediaConvertor, AlbumConvertor
from process.task import repeat_task
from typing import Union

import logging
import common.helper as helper

# 基础配置
helper.initLogger()
audio_convertor = AudioMediaConvertor()
album_convertor = AlbumConvertor()
dashboardConf = DashboardConf(
    id='nusic server',
    status=0,
    status_desc="运行正常",
    song_size=libaray.library_cache.songs.__len__(),
    library_conf=libaray.library_conf
)


class AppConf():
    acc_token: str = ""


appConf = AppConf()


async def guard(x_token: str = Header(title="密钥")):
    if x_token != appConf.acc_token:
        raise HTTPException(status_code=401, detail="验证失败")
    return x_token

# 路由配置
app = FastAPI(
    title="NAS Music Server API",
    description="管理 NAS 上的音乐文件，并为客户端简单快速地访问提供支持。",
    version="0.0.1"
)


@app.on_event("startup")
@repeat_task(seconds=600)
def clean_tempfile():
    """定时清理缓存文件"""
    logging.info("清理缓存文件...")
    logging.info("共删除{0}个文件".format(helper.clean_tempfile(512 * 1024 * 1024)))


@app.on_event("startup")
@repeat_task(seconds=6 * 60 * 60, wait_first=True)
def collect_resources():
    """定时整理资源"""

    # 音乐扫描（文件位置调整）
    dashboardConf.status = 1
    dashboardConf.status_desc = "扫描中……"
    libaray.scan_music()
    dashboardConf.status = 0
    dashboardConf.status_desc = "运行正常"

    # 空文件夹清理
    helper.clean_empty_folder(libaray.library_conf.basedir, [
                              libaray.library_conf.library_path, libaray.library_conf.conf_path])


@app.on_event("startup")
def startup():
    # 用户配置
    settings.read_conf()
    settings.check_conf()
    dashboardConf.id = settings.conf.get("base", "server_id")
    appConf.acc_token = helper.md5(settings.conf.get("base", "pass"))
    print(f"access token is [{appConf.acc_token}]")

    # 初始化资料库
    libaray.init(settings.conf.get("base", "work_folder"),
                 settings.conf.get("base", "collect_type"),
                 settings.conf.get("base", "audio_pattern"))

    # 扫描音乐
    dashboardConf.status = 1
    dashboardConf.status_desc = "扫描中……"
    libaray.scan_music()
    dashboardConf.status = 0
    dashboardConf.status_desc = "运行正常"


@app.middleware("http")
async def log_requests(request, call_next):
    """记录请求日志"""
    request_id = helper.random_str()
    logging.info(f"request_id={request_id}, path={request.url.path}")
    start_time = time.time()

    response = await call_next(request)

    process_time = (time.time() - start_time) * 1000
    formatted_process_time = '{0:.2f}'.format(process_time)
    logging.info(
        f"request_id={request_id}, completed_in={formatted_process_time}ms status_code={response.status_code}")

    return response


@app.get("/", response_model=DashboardConf, dependencies=[Depends(guard)])
async def root():
    """服务基础信息"""

    dashboardConf.song_size = libaray.library_cache.songs.__len__()
    return dashboardConf


@app.get("/songs/page/{page_index}", dependencies=[Depends(guard)], response_model=Page)
async def songs(page_index: int):
    """分页获取全部音乐"""
    # 排序
    libaray.library_cache.songs.sort(key=lambda x: x.add_time, reverse=True)
    return libaray.page_songs(page_index=page_index, page_size=30)


@app.get("/resources/{hashcode}", dependencies=[Depends(guard)])
async def resources(
        hashcode: str,
        mime: Union[str, None] = Query(
            default=None, title="音频类型", description="为空默认返回原始文件", regex="(aac|mid|mp3|m4a|ogg|flac|wav|amr|aiff)"),
        bitrate: Union[str, None] = Query(
            default=None, title="比特率", regex="(16k|24k|40k|56k|64k|112k|128k|160k|192k|256k|320k|550k)"),
        frame_rate: Union[int, None] = Query(default=None, title="采样率", description="参考值(8000|11025|22050|32000|44100|47250|48000|50000|96000|192000)")):
    """获取音乐资源"""

    filepath = audio_convertor.get_file_path(
        key=hashcode,
        songs=libaray.library_cache.songs,
        mime=mime,
        frame_rate=frame_rate,
        bitrate=bitrate
    )
    if filepath is None:
        raise HTTPException(status_code=404, detail="未找到音频资源或格式转换失败")
    return FileResponse(filepath)


@app.get("/resources/albums/{hashcode}", dependencies=[Depends(guard)])
async def album_image_resources(hashcode: str):
    """获取音乐专辑图片资源"""
    song = libaray.findSongByHashcode(hashcode)
    if song is not None:
        filepath = album_convertor.saveAlbumTemprary(song)
        if filepath is not None:
            return FileResponse(filepath)

    return HTTPException(status_code=404, detail="未找到专辑资源或格式转换失败")
